#!/usr/bin/python
# -*-coding:utf-8-*-
import pickle
import os
from time import time
import datetime
from datetime import timedelta
from scipy import stats
import statsmodels.api as sm
import pandas as pd
import numpy as np

try:
    try:
        from zg_factor_analysis_module.base.FactorAnalysisLibDerivative import FactorAnalysisLibDerivative
    except:
        from .base.FactorAnalysisLibDerivative import FactorAnalysisLibDerivative
except:
    from base.FactorAnalysisLibDerivative import FactorAnalysisLibDerivative

# from factor_re import Factor_Regression_analysis
save_dir_dict = {'000905':'/db/zg_data/zbc/factor_analysis_result/zz500/20190327/g5',
                 '000906':'/db/zg_data/zbc/factor_analysis_result/zz800',
                 '399102':'/db/zg_data/zbc/factor_analysis_result/cyb',
                 '000985':'/db/zg_data/zbc/factor_analysis_result/zzqz/hs300_benchmark',#'/db/zg_factors_lib/wsc/factor_analysis_result/zzqz',
                 '000852':'/db/zg_data/zbc/factor_analysis_result/zz1000',
                 '000966':'/db/zg_data/zbc/factor_analysis_result/jb400',
                 '000300':'/db/zg_data/zbc/factor_analysis_result/hs300',
                 '399101':'/db/zg_data/zbc/factor_analysis_result/zxb',
                 '399001':'/db/zg_data/zbc/factor_analysis_result/szcz',
                 '000001':'/db/zg_data/zbc/factor_analysis_result/szzs',
                 '399106':'/db/zg_data/zbc/factor_analysis_result/szzz'}

pool_result_save_dir='/db/zg_data/zbc/factor_analysis_result'
wsc_basic_data_dir='/db/zg_factors_lib/wsc/basic_data'

if not os.path.exists(pool_result_save_dir):
    os.makedirs(pool_result_save_dir)

# if not os.path.exists(wsc_basic_data_dir):
#     os.makedirs(wsc_basic_data_dir)

class Factor_Analysis(FactorAnalysisLibDerivative):
    def __init__(self,
                 start_date,
                 end_date,
                 quantile=5,
                 predictPeriod=21,
                 rebalance=21,
                 pool='000905',
                 benchmark='000985',
                 save_sub_dir=None,
                 dir_name='wsc'):
        super(Factor_Analysis, self).__init__()
        self.start_date=start_date
        self.end_date=end_date

        #self.trade= get_trade_data()
        #self.auxilliary_info = get_auxilliary_info()
        #self.index_component = get_index_component()

        self.predictPeriod =predictPeriod
        self.pool = pool
        self.benchmark=benchmark
        self.dir_name=dir_name

        save_dir = save_dir_dict[self.pool]

        if save_sub_dir is not None:
            save_dir = os.path.join(save_dir, save_sub_dir)

            if not os.path.exists(save_dir):
                os.makedirs(save_dir)

        self.save_dir = save_dir

        self.trade_date = self.read_basic_data_table(filename='processed_trade_date_data')\
            .drop_duplicates(subset=['trade_date']).reset_index(drop=True)
        self.trading_days= self.trade_date.loc[( self.trade_date['trade_date'] >= pd.to_datetime( self.start_date)) &
                                                ( self.trade_date['trade_date'] <= pd.to_datetime( self.end_date)),
                                                'trade_date'].tolist()

        #self.trade_date =self.auxilliary_info.get_trading_days(self.start_date, self.end_date, count=100000)
        #self.trading_days = list(pd.to_datetime(self.trade_date))
        self.quantile=quantile
        self.rebalance=rebalance
        self.month_start, self.month_end = self.get_month_start_and_end_date()

        if not os.path.exists(self.save_dir):
            os.makedirs(self.save_dir)

    def initialize(self):
        #self.sw1_data = self.get_sw1_data()
        #self.ci1_data = self.get_ci1_data()
        self.st_data = self.get_st_data()
        self.index_com=self.get_index_component_data()
        self.circulate_size = self.get_circulate_size_data()
        self.trade_data = self.get_trade_data()
        self.quote_rate=self.cal_stock_quote_rate()
        self.list_data=self.get_list_stock_data()

        is_update_daily_stock_pool = False

        if not is_update_daily_stock_pool:
            self.filtered_stocks = pd.read_pickle(
                os.path.join(wsc_basic_data_dir, self.pool + '_daily_filtered_stocks.pkl'))
        else:
            if self.pool is None:
                #self.filtered_stocks =self.get_pool_daily_filtered_all_stocks()
                self.filtered_stocks=pd.read_pickle(os.path.join(wsc_basic_data_dir,'daily_filtered_stocks_all.pkl'))
            else:
                #self.filtered_stocks=self.get_pool_daily_filtered_stocks()
                self.filtered_stocks=pd.read_pickle(os.path.join(wsc_basic_data_dir,self.pool+ '_daily_filtered_stocks.pkl'))

        #self.filtered_stocks=pd.read_pickle(os.path.join(self.rank_ic_save_dir, 'zz500_daily_filtered_stocks.pkl'))
        #self.filtered_stocks=pd.read_pickle(os.path.join(self.rank_ic_save_dir, 'zz500_daily_filtered_stocks.pkl'))
        #self.filtered_stocks = self.get_pool_daily_filtered_stocks()
        self.bench = self.get_bench_return()

        print('initialize finish !')

    def get_month_start_and_end_date(self):
        ys=int(self.start_date[0:4])
        ye=int(self.end_date[0:4])
        month_start=[]
        month_end=[]
        for y in range(ys,ye+1):
            for m in range(1,13):
                m_start=datetime.datetime(y,m,1).strftime('%Y-%m-%d')
                if m_start<=self.end_date and  m_start>=self.start_date:
                    month_start.append(m_start)
                if m ==12:
                    m_end=datetime.datetime(y,12,31).strftime('%Y-%m-%d')
                else:
                    m_end=(datetime.datetime(y,m+1,1)-datetime.timedelta(days=1)).strftime('%Y-%m-%d')
                if m_end<=self.end_date and  m_end>=self.start_date:
                    month_end.append(m_end)
        return month_start,month_end

    #TODO 计算基准收益
    def get_bench_return(self):
        '''
        if self.pool is None:
            bench=pd.DataFrame(index=self.trading_days,columns=['quote_rate'])
            for date in self.trading_days:
                stocks=self.filtered_stocks[date]
                bench['quote_rate'][date]=self.trade_data.xs(date)['quote_rate'].loc[stocks].mean()
        else:
        '''
        bench_data = self.read_basic_data_table(filename='processed_daily_index_trade_data',
                                                columns=['date', 'close', 'index_code'],
                                                filter_list=[
                                              "date >= '%s' and date <= '%s'" % (self.start_date, self.end_date)])
        bench = bench_data[bench_data['index_code'] == self.benchmark][['date', 'close']]
        bench['quote_rate'] = bench['close'].pct_change(1)
        bench.set_index('date', inplace=True)
        return bench['quote_rate']

    #获取交易数据,设置索引date,code
    def get_trade_data(self):
        trade_data=self.read_basic_data_table(filename='processed_daily_stock_trade_data',
                                              columns=['code',
                                       'open',
                                       'high',
                                       'low',
                                       'date',
                                      'close',
                                       'back_adjfactor'],  # 收盘价
                              filter_list=["date >= '%s' and date <= '%s'" % (self.start_date,self.end_date)])
        trade_data['close_back'] =trade_data['close'] * trade_data['back_adjfactor']
        trade_data['open_back'] =trade_data['open'] * trade_data['back_adjfactor']
        trade_data.set_index(['date', 'code'], inplace=True)
        trade_data['quote_rate']=trade_data.groupby('code')['close_back'].pct_change(1)
        return trade_data

    #申万一级行业数据
    def get_sw1_data(self):
        sw1_data=self.read_basic_data_table(filename='processed_daily_sw1_index_components_data',
                                            columns=['date', 'thscode', 'indcode'],
                                            filter_list = ["date >= '%s' and date <= '%s'" % (self.start_date, self.end_date)])
        sw1_data=sw1_data.sort_values(by=['date', 'thscode'], ascending=True)
        sw1_data.set_index(['date','thscode'],inplace=True)
        sw1_data=sw1_data.groupby('thscode').fillna(method='ffill')
        return sw1_data
    #行业数据,中信一级
    def get_ci1_data(self):
        ci1_data = self.read_basic_data_table(filename='processed_daily_ci1_index_components_data',
                                              columns=['date', 'thscode', 'indcode'],
                                              filter_list=["date >= '%s' and date <= '%s'" % (self.start_date, self.end_date)])

        ci1_data=ci1_data.sort_values(by=['date', 'thscode'], ascending=True)
        ci1_data.set_index(['date', 'thscode'], inplace=True)
        ci1_data=ci1_data.groupby('thscode').fillna(method='ffill')
        return ci1_data

    # 流通市值数据
    def get_circulate_size_data(self):
        circulate_size=self.read_factor_table(filename='scale_circulate_market_size',
                                   filter_list=["date >= '%s' and date <= '%s'" % (self.start_date, self.end_date)])
        circulate_size.set_index(['date','stock_code'],inplace=True)
        return circulate_size

    # ST数据
    def get_st_data(self):
        st_data = self.read_basic_data_table(filename='processed_is_st_data',
                                             columns=['code', 'date', 'is_st'],
                                             filter_list=["date >= '%s' and date <= '%s'" % (self.start_date, self.end_date)])
        st_data.set_index(['date', 'code'], inplace=True)
        return st_data

    def get_index_component_data(self):
        com_data = self.read_basic_data_table(filename='processed_common_index_daily_component_data',
                                              columns=['date', 'thscode', 'indcode'],
                                              filter_list=[
                                         "date >= '%s' and date <= '%s'" % (self.start_date, self.end_date)])
        index_data = com_data[com_data['indcode'] == self.pool].set_index('date')['thscode']
        return index_data

    #因子数据提取
    def get_total_factor_data(self,factor_name):#提取因子数据,设置索引 date,stock_code
        if self.dir_name is 'style':
            factor_data=self.read_style_table(filename=factor_name,
                                              filter_list=["date >= '%s' and date <= '%s'" % (self.start_date,self.end_date)])
        elif self.dir_name is 'wsc':
            factor_data=self.read_zbc_factor_table(filename=factor_name,
                                                   filter_list=["date >= '%s' and date <= '%s'" % (self.start_date,self.end_date)])
        else:
            factor_data = self.read_factor_table(filename=factor_name,
                                                    filter_list=["date >= '%s' and date <= '%s'" %
                                                                 (self.start_date, self.end_date)])

        factor_data.rename(columns={'stkcode': 'stock_code', 'code': 'stock_code'}, inplace=True)

        factor_data =factor_data.drop_duplicates(subset=['date', 'stock_code'], keep='last')

        factor_data.set_index(['date','stock_code'],inplace=True)

        return factor_data

    #获取某日的股票池数据
    def get_index_stock(self,date):
        stocks=sorted(self.index_com[date].tolist())
        return stocks

    #获取某日的全A股票池
    def get_all_stocks(self,date):
        stocks=sorted(self.trade_data.xs(date).index.tolist())
        return stocks

    # 获取给定股票列表在某日的一级行业分类
    def get_stocks_ind_data(self,stock_list,date,ind_name):
        #ind_name: cil 中信一级, sw1  申万一级
        if ind_name=='ci1':
            return self.ci1_data.xs(pd.to_datetime(date))['indcode'].loc[stock_list]
        elif ind_name=='sw1':
            return self.sw1_data.xs(pd.to_datetime(date))['indcode'].loc[stock_list]

    def get_list_stock_data(self):
        list_data = self.read_basic_data_table('processed_stock_list_delist_info_data')
        list_data.set_index('code', inplace=True)
        return list_data

    # 获取给定股票列表在某日的收盘价数据
    def get_stock_price_one(self,stock_list, date, fq='back'):
        if fq is None:
            return self.trade_data.xs(pd.to_datetime(date))['close'].loc[stock_list]
        elif fq == 'back':
            return self.trade_data.xs(pd.to_datetime(date))['close_back'].loc[stock_list]

    # 获取给定股票列表在区间的收盘价数据
    def get_stock_price(self,stock_list, start_date, end_date, fq=None):
        trade_data =self.trade_data.sort_index(level='date')
        if fq is None:
            temp=trade_data.loc(axis=0)[(slice(pd.to_datetime(start_date), pd.to_datetime(end_date)), stock_list)]['close']
        elif fq=='back':
            temp=trade_data.loc(axis=0)[(slice(pd.to_datetime(start_date), pd.to_datetime(end_date)), stock_list)]['close_back']
        return temp

    def get_stock_quote_rate(self, stock_list, start_date, end_date):
        return self.quote_rate.loc[pd.to_datetime(start_date):pd.to_datetime(end_date),stock_list]

    #获取给定股票列表在区间的累计收益率数据
    def get_stock_period_return(self,stock_list, start_date, end_date):# start_data的收盘价开始计算,结果不包括start_date
        price=self.get_stock_price(stock_list, start_date, end_date,fq='back')
        price=price.reset_index()
        close = pd.pivot_table(price, index='date', columns='code', values='close_back')
        return close.iloc[-1]/close.iloc[0]-1

    # 获取给定股票列表在某日的因子数据
    def get_factor_data_oneday(self,factor_data,stock_list,date):
        return factor_data.xs(pd.to_datetime(date))[factor_data.columns[0]].loc[stock_list]

    # 获取给定股票列表在某日的市值数据
    def get_size_data_oneday(self,stock_list,date):
        return self.circulate_size.xs(date)[self.circulate_size.columns[0]].loc[stock_list]

    # ST股票过滤
    def filter_st_stock(self,stock_list, date):
        st=self.st_data.xs(date).loc[stock_list]
        return st[st['is_st'] == 0].index.tolist()

    def get_trade_date(self,start,end):
        return self.trade_date.loc[(self.trade_date['trade_date'] >= pd.to_datetime(start)) &
                            (self.trade_date['trade_date'] <= pd.to_datetime(end)),
                            'trade_date'].astype('str').tolist()

    # 新股过滤
    def filter_new_stock(self,stock_list, date, n=252):
        date=pd.to_datetime(date)
        list_data = self.list_data.copy()
        list_data['delist_date'] = list_data['delist_date'].apply(lambda x: date if x is None else x)
        list_data['list_date'] = pd.to_datetime(list_data['list_date'])
        list_data['time_delta'] = list_data['delist_date'] - list_data['list_date']
        return list_data.loc[stock_list][list_data.loc[stock_list].time_delta > timedelta(days=n)].index.tolist()

    # 一字板股票过滤cal
    def filter_board_stock(self,stock_list, date):
        trade_data =self.trade_data.xs(date).loc[stock_list]
        board = trade_data[(trade_data.close == trade_data.open) & (trade_data.close == trade_data.high) & (
        trade_data.close == trade_data.low)].index
        return trade_data.index.difference(board).tolist()

    #涨停、停牌股过滤
    def filter_buy_limit_stock(self,stock_list, date):
        trade_data = self.trade_data.xs(date).loc[stock_list]
        quote_rate=self.quote_rate[stock_list].ix[date]
        buy_limit=trade_data[(trade_data.close == trade_data.open) & (trade_data.close == trade_data.high) & (
        trade_data.close == trade_data.low)].index.intersection(quote_rate[quote_rate>=0].index)
        return trade_data.index.difference(buy_limit).tolist()

    #跌停、停牌股过滤
    def filter_sell_limit_stock(self,stock_list, date):
        trade_data = self.trade_data.xs(date).loc[stock_list]
        quote_rate = self.quote_rate[stock_list].ix[date]
        sell_limit=trade_data[(trade_data.close == trade_data.open) & (trade_data.close == trade_data.high) & (
        trade_data.close == trade_data.low)].index.intersection(quote_rate[quote_rate<=0].index)
        return trade_data.index.difference(sell_limit).tolist()

    #计算向前N期的收益
    def cal_forward_return(self):
        price = self.trade_data['close_back'].reset_index()
        close = pd.pivot_table(price, index='date', columns='code', values='close_back')
        forward_return= close.pct_change(self.predictPeriod).shift(-self.predictPeriod)
        return forward_return.stack()

    #计算收益率
    def cal_stock_quote_rate(self):
        price = self.trade_data['close_back'].reset_index()
        price['quote_rate'] =price.groupby('code').pct_change(1)
        quote_rate = pd.pivot_table(price, index='date',columns='code', values='quote_rate')
        return quote_rate

    #计算股票池股票所属行业权重
    def cal_ind_weight(self,ind_name='ci1'):
        # 获取指数权重数据
        index_component = self.read_basic_data_table('processed_daily_index_component_weight_data',
                                                     filter_list=["date >= '%s'and date <= '%s'" % (self.start_date, self.end_date)])
        index_component['code'] = index_component['code'].apply(lambda x: x + '.SH' if x[0] is '6' else x + '.SZ')
        # 筛选给定股票池的数据
        pool_comp = index_component[index_component['indcode'] == self.pool][['date', 'code', 'weight']]
        # 数据去重
        pool_comp.drop_duplicates(subset=['date', 'code'], keep='last', inplace=True)
        # 排序
        pool_comp = pool_comp.sort_values(by=['date', 'code'], ascending=True)
        # 设置索引
        pool_comp.set_index(['date', 'code'], inplace=True)
        # 提取行业数据
        ind = pool_comp.groupby('date').apply(
            lambda x:self.get_stocks_ind_data(sorted(x.index.get_level_values('code').tolist()),
                                            x.index.get_level_values('date')[0], ind_name))
        # 去除重复索引
        ind = ind.reset_index().drop_duplicates(subset=['date', 'thscode']).set_index(['date', 'thscode'])
        # 赋值
        pool_comp['ind'] = ind
        # 填充行业缺失值为unknow
        pool_comp['ind'].fillna('unknow', inplace=True)
        # 计算行业权重函数
        def cal_ind_weihgt(df):
            df['ind_weight'] = df['weight'].sum()
            return df

        # 计算所属行业权重
        pool_comp = pool_comp.groupby(['date', 'ind']).apply(lambda x: cal_ind_weihgt(x))
        return pool_comp[['ind','ind_weight']]

    #获取过滤后的每日股票列表
    def get_pool_daily_filtered_stocks(self):
        '''
        pool_name_map = {
            '000905': 'ZZ500',
            '000300': 'HS300'
        }

        if os.path.exists(os.path.join(self.rank_ic_save_dir, '%s_daily_filtered_stocks.pkl' % (pool_name_map[self.pool]))):
            return pd.read_pickle(os.path.join(self.rank_ic_save_dir, '%s_daily_filtered_stocks.pkl' % (pool_name_map[self.pool])))
        '''
        filtered_stocks={}
        for date in self.trading_days:
            try:
                stocks =self.get_index_stock(date)

                #ST股过滤
                stocks = self.filter_st_stock(stocks, date)
                #新股过滤
                stocks = self.filter_new_stock(stocks, date)

                #停牌股/一字板股票过滤
                stocks = self.filter_board_stock(stocks, date)

                filtered_stocks[date]=stocks
            except:
                pass
        output = open(os.path.join(wsc_basic_data_dir, '%s_daily_filtered_stocks.pkl' % (self.pool)), 'wb')

        #output = open(os.path.join(self.rank_ic_save_dir, '%s_daily_filtered_stocks.pkl' % (self.pool)), 'wb')

        #output = open(os.path.join(self.rank_ic_save_dir, '%s_daily_filtered_stocks.pkl' % (pool_name_map[self.pool])), 'wb')

        pickle.dump(filtered_stocks, output)
        output.close()
        print('Stock pool filter finish !')
        return filtered_stocks


    #获取过滤后的每日股票列表
    def get_pool_daily_filtered_all_stocks(self):
        filtered_stocks={}
        for date in self.trading_days:
            print(date)
            try:
                stocks =self.get_all_stocks(date)
                #ST股过滤
                stocks = self.filter_st_stock(stocks, date)
                #新股过滤
                stocks = self.filter_new_stock(stocks, date)
                #停牌股/一字板股票过滤
                stocks = self.filter_board_stock(stocks, date)
                filtered_stocks[date]=stocks
            except Exception as e:
                print(e)
                pass
        out_put=open(os.path.join(wsc_basic_data_dir, 'daily_filtered_stocks_all.pkl'),'wb')
        pickle.dump(filtered_stocks,out_put)
        out_put.close()
        return filtered_stocks

    #计算一个因子的Rank_ic
    def cal_factor_rank_ic(self,factor_forward_return_data):
        s=time()
        rank_ic=pd.Series(index=self.trade_date[0:-self.predictPeriod])
        for date in rank_ic.index:
            try:
                stocks =self.filtered_stocks[date]
                temp = factor_forward_return_data.xs(date).loc[stocks]
                rank_ic[date]=temp.rank().corr().iloc[0,1]
            except:
                rank_ic[date]=np.nan
        e=time()
        print(e-s)
        return rank_ic

    #计算一天的Rank_ic
    def cal_rank_ic(self,df):
        try:
            date=df.reset_index().date[0]
            stocks =self.filtered_stocks[date]
            data=df.dropna()
            try:
                data=data.set_index('stock_code')
            except:
                data=data.set_index('code')
            data=data.loc[stocks]
            data.dropna(inplace=True)
            ic=stats.spearmanr(data.iloc[:,1].values,data.iloc[:,2].values)[0]
            return ic
        except Exception as e:
            print(e)
            return np.nan

    #计算给定因子列表的rank_ic
    def cal_factors_rank_ic(self,factor_list,save_name='factor_rank_ic_result'):
        #self.initialize()
        ic_data =pd.DataFrame(index=pd.to_datetime(self.trading_days), columns=factor_list)
        #ic_data=pd.read_csv(os.path.join(F.rank_ic_save_dir," factor rank ic.csv"),index_col=0)#
        #ic_data.index=pd.to_datetime(ic_data.index)
        #提取向前滚动predictPeriod期的累计收益
        forward_return = self.cal_forward_return()
        for factor_name in factor_list:
            print(factor_name)
            if factor_name.startswith('event') or factor_name.startswith('timing'):
                pass
            else:
                try:
                    st = time()
                    #提取因子数据
                    factor_data = self.get_total_factor_data(factor_name)

                    #索引处理
                    comindex = ic_data.index.intersection(factor_data.index.get_level_values('date'))
                    #数据合并
                    factor_data['forward_return']=forward_return.loc[factor_data.index]
                    #factor_data[factor_name]=factor_data.groupby('stock_code').shift(self.predictPeriod)
                    factor_data=factor_data.reset_index()

                    #计算因子Rank_IC
                    ic_data[factor_name].loc[comindex]= factor_data.groupby('date').apply(lambda x: self.cal_rank_ic(x)).loc[comindex]

                    ic_data[factor_name]=ic_data[factor_name].shift(self.predictPeriod)

                    ic_data.index.name='date'

                    ic_data.to_csv(os.path.join(self.rank_ic_save_dir, '%s.csv'%save_name), encoding='utf-8')

                    et=time()

                    print(et-st)

                #return ic_data
                except Exception as e:
                    print(e)
                    pass
            #return ic_data

    #中位数去极值
    def winsorize_med(self,factor,n=3*1.4826):
        data=factor.copy()
        data.dropna(inplace=True)
        D_M=data.median()
        ls_deviation=abs(data-D_M)
        D_MAD=ls_deviation.median()
        lower=D_M-n*D_MAD
        upper=D_M+n*D_MAD
        data=data.apply(lambda x: lower if x<lower else upper if x>upper else x)
        return data

    #Rank 标准化
    def rank_normal(self,factor):
        r=factor.rank()
        return (r-r.mean())/r.std()

    #加权标准化
    def weight_normalization(self,factor,weight):
        w_mean=np.average(factor,weights=weight)
        std=factor.std()
        return (factor-w_mean)/std

    #Z_Score标准化
    def z_score_normalization(self,factor):
        return (factor-factor.mean())/factor.std()

    #行业中性化处理
    def industry_neutral(self,factor,date,ind_name):
        ind=self.get_stocks_ind_data(factor.index.tolist(),date,ind_name)
        ind_data=pd.get_dummies(ind)
        df=pd.concat([factor,ind_data],axis=1)
        df.dropna(inplace=True)
        results=sm.OLS(df.iloc[:,0],df.iloc[:,1:]).fit()
        return results.resid

    #市值中性化处理
    def cap_neutral(self,factor,date):
        size =self.get_size_data_oneday(factor.index.tolist(),date)
        df=pd.concat([factor,np.log(size)],axis=1)
        df.dropna(inplace=True)
        results=sm.OLS(df.iloc[:,0],df.iloc[:,1:]).fit()
        return results.resid


    # 获取分组股票池
    def get_factor_stock(self,factor_data,date):
        # 股票池获取
        stocks = self.filtered_stocks[date]
        # 因子数据提取
        factor = self.get_factor_data_oneday(factor_data,stocks,date)
        factor.dropna(inplace=True)
        factor=self.rank_normal(factor)
        factor=self.winsorize_med(factor)

        # 分组
        factor_q = pd.qcut(factor.rank(method='first'), self.quantile, labels=False) + 1

        quantile_stock_dict = {}

        for i in range(self.quantile):
            quantile_stock_dict[i + 1] = factor_q[factor_q == i + 1].index.tolist()

        return quantile_stock_dict

    #获取市值分层分组股票池
    def get_factor_size_grouped_stock(self,factor_data,date,groupnum=5):
        # 股票池获取
        stocks = self.filtered_stocks[date]
        # 因子数据提取
        factor = self.get_factor_data_oneday(factor_data, stocks, date)
        factor.dropna(inplace=True)
        size =self.get_size_data_oneday(factor.index.tolist(),date)
        df=pd.concat([factor,np.log(size)],axis=1)
        df.dropna(inplace=True)
        #市值分层
        grouping = pd.qcut(df.iloc[:, 1].rank(method='first'),groupnum, labels=False)
        #按照因子进行分层分组
        grouped = df.iloc[:,0].rank(method='first').groupby(grouping).apply(pd.qcut,self.quantile,labels=False)+1
        quantile_stock_dict = {}
        for i in range(self.quantile):
            quantile_stock_dict[i + 1] =grouped[grouped== i + 1].index.tolist()
        return quantile_stock_dict

    #获取行业分层分组股票池
    def get_factor_ind_grouped_stock(self,factor_data,date,ind_name='ci1'):
        # 股票池获取
        stocks = self.filtered_stocks[date]
        # 因子数据提取
        factor = self.get_factor_data_oneday(factor_data, stocks, date)
        factor.dropna(inplace=True)
        #行业数据
        ind =self.get_stocks_ind_data(stocks, date, ind_name)
        df=pd.concat([factor,ind],axis=1)
        df.dropna(inplace=True)
        #行业分层
        grouping =df.iloc[:,1]
        #按照因子进行分层分组——此处有BUG 当行业内股票的数量小于分组数事，Q_cut会报错：Bin edges must be unique
        grouped = df.iloc[:,0].rank(method='first').groupby(grouping).apply(pd.qcut,self.quantile,labels=False)+1
        quantile_stock_dict = {}
        for i in range(self.quantile):
            quantile_stock_dict[i + 1] =grouped[grouped== i + 1].index.tolist()
        return quantile_stock_dict

    #计算给定股票经行业调整后的权重
    def cal_ind_adj_weight(self,stock_list,date):
        #提取一天的行业权重数据
        ind_weight =self.ind_weight.xs(date).loc[stock_list]
        '''
        #提取流通市值数据
        ind_weight['cap'] =self.get_size_data_oneday(ind_weight.index.tolist(), date)

        #计算行业调整的个股权重——市值权重
        def cal_stock_weight(df):
            df['ind_adj_weight'] = df['cap'] / df['cap'].sum() * df['ind_weight']
            return df
        '''

        # 计算行业调整的个股权重
        def cal_stock_weight(df):
            df['ind_adj_weight'] = df['ind_weight']/len(df)
            return df
        ind_adj_weight = ind_weight.groupby('ind').apply(lambda x: cal_stock_weight(x))
        #权重归一化处理
        ind_adj_weight['ind_adj_weight'] = ind_adj_weight['ind_adj_weight'] / ind_adj_weight['ind_adj_weight'].sum()
        return ind_adj_weight['ind_adj_weight']

    # 计算分组收益
    def cal_quantile_return_one_period(self,quantile_stock_dict,start,end,weight='equal'):  # 权重:equal / cap
        try:
            quantile_name = ['q'+str(i) for i in quantile_stock_dict.keys()]
            trade_date=self.get_trade_date(start,end)#self.auxilliary_info.get_trading_days(start,end)
            trading_days = list(pd.to_datetime(trade_date))
            quantile_return = pd.DataFrame(index=trading_days[1:], columns=quantile_name)
            daily_position_data=pd.DataFrame()
            for q in quantile_stock_dict.keys():
                stocks = quantile_stock_dict[q]
                if '000022.SZ' in stocks:
                    stocks[stocks.index('000022.SZ')]='001872.SZ'
                buy_stock =self.filter_buy_limit_stock(stocks,trading_days[0])
                if weight is 'cap':
                    cap=self.get_size_data_oneday(buy_stock,trading_days[0])
                    cap_weight=cap/cap.sum()
                    ret=self.get_stock_quote_rate(buy_stock,trading_days[1],trading_days[-1])
                    cal_index=sorted(ret.columns.intersection(cap_weight.index))
                    weights=cap_weight.ix[cal_index].fillna(0)/cap_weight.ix[cal_index].sum()
                    weights.name = 'weight'
                    quantile_return.iloc[:,q-1]=ret.apply(lambda x: np.average(x.ix[cal_index].fillna(0), weights=weights), axis=1)
                elif weight is 'ind_adj':
                    #按照基准行业权重配置
                    ind_adj_weight=self.cal_ind_adj_weight(buy_stock,trading_days[0])
                    ret=self.get_stock_quote_rate(buy_stock,trading_days[1],trading_days[-1])
                    cal_index=sorted(ret.columns.intersection(ind_adj_weight.index))
                    weights=ind_adj_weight.ix[cal_index].fillna(0)/ind_adj_weight.ix[cal_index].sum()
                    weights.name = 'weight'
                    quantile_return.iloc[:,q-1]=ret.apply(lambda x: np.average(x.ix[cal_index].fillna(0), weights=weights), axis=1)
                else:
                    #等权处理
                    quantile_return.iloc[:,q-1] = self.get_stock_quote_rate(buy_stock, trading_days[1],trading_days[-1]).mean(axis=1)
                    weights=pd.Series(index=buy_stock)
                    weights=weights.fillna(1/len(buy_stock))
                    weights.name = 'weight'
                daily_position=pd.DataFrame(weights)
                daily_position['transfered_date']=daily_position['date'] = trading_days[0]
                daily_position['recall_date'] =trading_days[-1]
                daily_position['quantile']='q'+str(q)
                daily_position= daily_position.reset_index()
                daily_position.rename(columns={0: 'weight', 'index': 'stock_code'}, inplace=True)
                daily_position_data=daily_position_data.append(daily_position,ignore_index=True)
            #手续费扣除
            #quantile_return.ix[trading_days[-1]]=quantile_return.ix[trading_days[-1]]-0.003
            return quantile_return,daily_position_data
        except Exception as e:
            print(e)
            return None,None

    # 计算因子分组收益
    def cal_quantile_factor_return(self,factor_name, weight='equal',groupby=None):
        '''
        :param factor_name: 因子名称
        :param guoupby: 分层标准,可选：None(不分层)、ci1(中信一级行业分层)、sw1(申万一级行业分层)、cap(流通市值分层)
        :param weight:组合加权方式
        '''
        try:
            st = time()
            # print(factor_name)
            if self.rebalance is 'month_end':
                # 月末调仓
                rebalance_date = [self.get_trade_date(self.start_date, date)[-1] for date in
                                  self.month_end]
                rebalance_date.append(self.trading_days[0].strftime('%Y-%m-%d'))
                rebalance_date = pd.to_datetime(sorted(list(set(rebalance_date))))
            elif self.rebalance is 'month_start':
                # 月初调仓
                rebalance_date = [self.get_trade_date(self.start_date, date)[-1] for date in
                                  self.month_start]
                rebalance_date.append(self.trading_days[0].strftime('%Y-%m-%d'))
                rebalance_date = pd.to_datetime(sorted(list(set(rebalance_date))))
            else:
                #按照给定交易日调仓
                rebalance_date = self.trading_days[0:len(self.trading_days):self.rebalance]

            quantile_name = ['q' + str(i) for i in range(1, self.quantile + 1)]
            factor_return = pd.DataFrame(index=self.trading_days[1:], columns=quantile_name)
            daily_position_all=pd.DataFrame()

            factor_data = self.get_total_factor_data(factor_name)

            for i in range(len(rebalance_date)):
                try:
                    #获取分组股票池
                    # print(rebalance_date[i])
                    if groupby is 'ci1':
                        quantile_stock_dict = self.get_factor_ind_grouped_stock(factor_data, rebalance_date[i], ind_name='ci1')
                    elif groupby is 'sw1':
                        quantile_stock_dict = self.get_factor_ind_grouped_stock(factor_data,rebalance_date[i], ind_name='sw1')
                    elif groupby is 'cap':
                        quantile_stock_dict=self.get_factor_size_grouped_stock(factor_data,rebalance_date[i], groupnum=5)
                    else:
                        quantile_stock_dict = self.get_factor_stock(factor_data, rebalance_date[i])

                    s = self.trading_days[self.trading_days.index(rebalance_date[i])]
                    if i < len(rebalance_date) - 1:
                        e = self.trading_days[self.trading_days.index(rebalance_date[i + 1])]
                    else:
                        e = rebalance_date[-1]#self.trading_days[-1]
                    if s != e:
                        ret,daily_position= self.cal_quantile_return_one_period(quantile_stock_dict,s,e,weight)

                        factor_return.loc[ret.index.tolist()] = ret

                        daily_position_all=daily_position_all.append(daily_position,ignore_index=True)
                except Exception as e:
                    print(e)
                    pass

            factor_return['top_to_bottom'] = factor_return['q' + str(self.quantile)] - factor_return['q1']

            factor_return['bench'] =self.bench.loc[factor_return.index]

            relative_return = factor_return.iloc[:, 0:self.quantile].apply(lambda x: x - factor_return['bench'])

            factor_return = factor_return.dropna(axis=0, how='all')

            relative_return=relative_return.dropna(axis=0, how='all')

            '''
            if self.dir_name == 'public':
                self.quantile_save_dir = '/db/zg_data/yuyue/factor_backtest_result/' + self.pool + '/daily_return'
                self.quantile_save_dir_position = '/db/zg_data/yuyue/factor_backtest_result/' + self.pool + '/daily_position'
           '''

            writer = pd.ExcelWriter(os.path.join(self.save_dir,
                                                 factor_name + ' factor groupby '+
                                                 str(groupby)+' '+str(weight)+' weight '+
                                                 str(self.pool)+' pool '+
                                                 str(self.rebalance)+' quantile new_test result.xlsx'))

            factor_return.to_excel(writer,'abs_return_result')

            relative_return.to_excel(writer,'relative_return_result')

            daily_position_all.to_excel(writer,'holding_detail')

            writer.save()
            et= time()
            print('%.4f sec' % (et-st))

            return factor_return, relative_return
        except Exception as e:
            print(e)
            return None,None

    def cal_annual_return(self,daily_return):
        cum_return = (1 + daily_return).cumprod()
        annual_return = cum_return.ix[-1] ** (250 * 1. / len(cum_return)) - 1
        return annual_return

    def cal_annual_vol(self,daily_return):
        return daily_return.std() * np.sqrt(250)

    def cal_sharpe(self,daily_return):
        annual_return = self.cal_annual_return(daily_return)
        annual_vol = self.cal_annual_vol(daily_return)
        sharpe = annual_return / annual_vol
        return sharpe

    def cal_winrate(self,daily_return):
        win_rate = len(daily_return[daily_return > 0]) / len(daily_return)
        return win_rate

    def cal_retuen_measure(self,factor_return,relative_return):
        #TODO 计算年化收益率
        measure_result=pd.DataFrame(index=['q1', 'q2', 'q3', 'q4', 'q5', 'q6', 'q7', 'q8',
                                           'q9', 'q10','top_to_bottom', 'bench'],
                                    columns=['annual_return','annual_vol','SR','abs_win_rate',
                                             'annual_excess_return','TE','IR','excess_win_rate'])
        measure_result['annual_return']=factor_return.dropna().apply(lambda x:self.cal_annual_return(x))
        measure_result['annual_vol']=factor_return.dropna().apply(lambda x:self.cal_annual_vol(x))
        measure_result['SR']=factor_return.dropna().apply(lambda x:self.cal_sharpe(x))
        measure_result['abs_win_rate']=factor_return.dropna().apply(lambda x:self.cal_winrate(x))
        measure_result['annual_excess_return']=relative_return.dropna().apply(lambda x:self.cal_annual_return(x))
        measure_result['TE']=relative_return.dropna().apply(lambda x:self.cal_annual_vol(x))
        measure_result['IR']=relative_return.dropna().apply(lambda x:self.cal_sharpe(x))
        measure_result['excess_win_rate']=relative_return.dropna().apply(lambda x:self.cal_winrate(x))

        return measure_result

    #计算因子列表的分组回测收益数据
    def cal_factor_list_return(self, factor_list, weight='equal',groupby=None, label=None):
        if not os.path.exists(pool_result_save_dir):
            os.makedirs(pool_result_save_dir)

        if label is None:
            out_filename = 'factors_groupby_' + str(groupby) + '_' + str(weight) + '_weight_' + str(self.pool) + '_pool_' + str(self.rebalance)
        else:
            out_filename = 'factors_groupby_' + str(groupby) + '_' + str(weight) + '_weight_' + str(self.pool) + '_pool_' + str(self.rebalance) + label

        writer = pd.ExcelWriter(os.path.join(pool_result_save_dir,
                                             out_filename + '.xlsx'))

        annual_return=pd.DataFrame(index=factor_list,columns=['q1',
                                                              'q2',
                                                              'q3',
                                                              'q4',
                                                              'q5',
                                                              'q6',
                                                              'q7',
                                                              'q8',
                                                              'q9',
                                                              'q10',
                                                              'top_to_bottom',
                                                              'bench'])

        annual_excess_return=pd.DataFrame(index=factor_list,columns=['q1',
                                                                     'q2',
                                                                     'q3',
                                                                     'q4',
                                                                     'q5',
                                                                     'q6',
                                                                     'q7',
                                                                     'q8',
                                                                     'q9',
                                                                     'q10',
                                                                     'top_to_bottom',
                                                                     'bench'])

        SR=pd.DataFrame(index=factor_list,columns=['q1',
                                                   'q2',
                                                   'q3',
                                                   'q4',
                                                   'q5',
                                                   'q6',
                                                   'q7',
                                                   'q8',
                                                   'q9',
                                                   'q10',
                                                   'top_to_bottom',
                                                   'bench'])

        TE=pd.DataFrame(index=factor_list, columns=['q1',
                                                    'q2',
                                                    'q3',
                                                    'q4',
                                                    'q5',
                                                    'q6',
                                                    'q7',
                                                    'q8',
                                                    'q9',
                                                    'q10',
                                                    'top_to_bottom',
                                                    'bench'])

        IR=pd.DataFrame(index=factor_list, columns=['q1',
                                                    'q2',
                                                    'q3',
                                                    'q4',
                                                    'q5',
                                                    'q6',
                                                    'q7',
                                                    'q8',
                                                    'q9',
                                                    'q10',
                                                    'top_to_bottom',
                                                    'bench'])

        annual_vol=pd.DataFrame(index=factor_list, columns=['q1',
                                                            'q2',
                                                            'q3',
                                                            'q4',
                                                            'q5',
                                                            'q6',
                                                            'q7',
                                                            'q8',
                                                            'q9',
                                                            'q10',
                                                            'top_to_bottom',
                                                            'bench'])

        abs_win_rate=pd.DataFrame(index=factor_list, columns=['q1',
                                                              'q2',
                                                              'q3',
                                                              'q4',
                                                              'q5',
                                                              'q6',
                                                              'q7',
                                                              'q8',
                                                              'q9',
                                                              'q10',
                                                              'top_to_bottom',
                                                              'bench'])

        excess_win_rate=pd.DataFrame(index=factor_list, columns=['q1',
                                                                 'q2',
                                                                 'q3',
                                                                 'q4',
                                                                 'q5',
                                                                 'q6',
                                                                 'q7',
                                                                 'q8',
                                                                 'q9',
                                                                 'q10',
                                                                 'top_to_bottom',
                                                                 'bench'])

        #公用数据提取
        #self.initialize()
        if weight == 'ind_adj':
            self.ind_weight = self.cal_ind_weight(ind_name='sw1')

        for factor_name in factor_list:
            '''
            if factor_name.startswith('event') or factor_name.startswith('timing'):
                pass
            else:
            '''
            try:
                print(factor_name)

                factor_return, relative_return = self.cal_quantile_factor_return(factor_name,
                                                                                 weight,
                                                                                 groupby)

                df = self.cal_retuen_measure(factor_return, relative_return)

                annual_return.loc[factor_name] = df['annual_return']

                annual_excess_return.loc[factor_name] = df['annual_excess_return']

                SR.loc[factor_name] = df['SR']

                IR.loc[factor_name] = df['IR']

                TE.loc[factor_name] = df['TE']

                annual_vol.loc[factor_name] = df['annual_vol']

                abs_win_rate.loc[factor_name] = df['abs_win_rate']

                excess_win_rate.loc[factor_name] = df['excess_win_rate']
            except Exception as e:
                print(e)
                pass

        annual_return.to_excel(writer, 'annual_return')

        annual_excess_return.to_excel(writer, 'annual_excess_return')

        SR.to_excel(writer, 'SR')

        IR.to_excel(writer, 'IR')

        TE.to_excel(writer, 'TE')

        annual_vol.to_excel(writer, 'annual_vol')

        abs_win_rate.to_excel(writer, 'abs_win_rate')

        excess_win_rate.to_excel(writer, 'excess_win_rate')

        writer.save()


def factor_quantile_main(start_date,
                         end_date,
                         factor_list,
                         quantile=5,
                         predictPeriod=21,
                         rebalance=21,
                         pool='000905',
                         benchmark='000905',
                         dir_name='public',
                         weight='ind_adj',
                         save_sub_dir=None,
                         label=None,
                         groupby='cap'):
    factor_analysis = Factor_Analysis(start_date=start_date,
                                      end_date=end_date,
                                      predictPeriod=predictPeriod,
                                      quantile=quantile,
                                      rebalance=rebalance,
                                      pool=pool,
                                      benchmark=benchmark,
                                      save_sub_dir=save_sub_dir,
                                      dir_name=dir_name)

    factor_analysis.initialize()

    factor_analysis.cal_factor_list_return(factor_list, weight, groupby, label=label)

def factor_rank_ic_main(start_date,
                         end_date,
                         factor_list,
                         save_name,quantile=5,
                         predictPeriod=21,
                         rebalance=21,
                         pool='000905',
                        dir_name='public',
                        weight='ind_adj',
                        groupby='cap'):
    factor_analysis=Factor_Analysis(start_date=start_date,
                                    end_date=end_date,
                                    predictPeriod=predictPeriod,
                                    quantile=quantile,
                                    rebalance=rebalance,
                                    pool=pool,
                                    dir_name=dir_name)

    factor_analysis.initialize()
    factor_analysis.cal_factors_rank_ic(factor_list,save_name)


if __name__ == '__main__':
    start_date = '2010-01-01'
    end_date = '2018-12-28'
    F = FactorAnalysisLibDerivative()
    #factor_analysis=Factor_Analysis(start_date,end_date,pool='000985')
    #factor_analysis.initialize()
    #filtered_stocks=factor_analysis.get_pool_daily_filtered_stocks()
    #t = F.show_factor_library_db()
    #factor_list = [f.split('.')[0] for f in t]

    #TODO 跑风格因子的因子回测结果

    factor_name='profitability_eps_recurring_ttm'
    factor_dir='/db/zg_factors_lib/public'
    file_list=list(os.walk(os.path.join(factor_dir)))[0][2]
    factor_list = sorted(list(set([f.split('.')[0] for f in file_list])))
    factor_management_dir = '/db/zg_factors_lib/factor_management'

    #factor_analysis.cal_quantile_factor_return(factor_name)
    #factor_list = pd.read_excel(os.path.join(factor_management_dir, 'factor_filtered_1129.xlsx')
                             #   , index_col=0)['factor_name'].tolist()

    factor_list=[
        # 'hf_liquidity_effective_bid_ask_spread_5d',
        # 'hf_liquidity_effective_bid_ask_spread_10d',
        # 'hf_liquidity_effective_bid_ask_spread_20d',
        # 'hf_liquidity_effective_bid_ask_spread_30d',
        # 'hf_cqy_20d',

        # 基本面
        'valuation_ep_recurring_ttm',
        'valuation_ep_attr2parnet_ttm',
        'valuation_ep_ttm',

        'profitability_mkt_relative_eps_3m',
        'profitability_roe_ttm',
        'profitability_eps_ttm',
        'profitability_ind_relative_gp_9m',

        'growth_roe_single_season_change_4q',
        'growth_eps_single_season_change_4q',
        'growth_eps_single_season_4q_div_8q',
        'growth_gross_margin_ttm_change_4q',
        'growth_eps_recurring_single_season_change_4q',

        # 波动率
        'tech_high_minus_low_r_month_std_1m',
        'tech_high_minus_low_r_month_std_3m',

        'tech_high_plus_low_r_month_std_1m',
        'tech_high_plus_low_r_month_std_3m',

        'tech_high_r_month_std_1m',
        'tech_high_r_month_std_3m',

        'tech_hpl_r_month_std_1m',
        'tech_hpl_r_month_std_3m',

        'tech_hml_r_month_std_1m',
        'tech_hml_r_month_std_3m',

        'tech_hl_bid_ask_spread_demean_vol_1m',
        'tech_hl_bid_ask_spread_demean_vol_3m',

        'tech_down_to_up_vol_1m',
        'tech_down_to_up_vol_3m',

        # 特色
        'tech_ff3_dispersion_1m',
        # 'tech_ff3_dispersion_3m',

        'tech_Carhart4_dispersion_1m',
        # 'tech_Carhart4_dispersion_3m',

        'tech_network_eigenvector_centrality_1m',
        'tech_network_degree_centrality_1m',

        # 其它
        'tech_overnight_jump_1m',
        'tech_overnight_jump_3m',
        'tech_tskew_60d',
        'tech_jump_gun_down_1m',
        'tech_jump_gun_up_1m',
        'tech_mkt_relative_trend_1m',

        # 动量
        'mom_relative_strength_1m',
        'mom_relative_strength_3m',
        'mom_relative_strength_6m',

        'mom_weighted_strength_1m',
        'mom_weighted_strength_3m',
        'mom_weighted_strength_6m',

        'mom_industrialadjust_1m',
        'mom_industrialadjust_3m',
        'mom_industrialadjust_6m',

        'mom_rps_1m',
        'mom_rps_3m',
        'mom_rps_6m',

        'mom_reverse_1m',
        'mom_reverse_3m',
        'mom_reverse_6m',

        # 流动性
        'tech_turnover_cv_1m',
        'tech_turnover_cv_3m',

        'tech_up_turnover_1m',
        'tech_up_turnover_3m',

        'tech_volume_trend_2m',
        'tech_volume_trend_3m',

        'liquidity_share_turnover_1m',
        'liquidity_share_turnover_3m',

        'liquidity_share_trade_volume_std_1m',
        'liquidity_share_trade_volume_std_3m',

        'liquidity_log_turnover_price_1m',
        'liquidity_log_turnover_price_3m',

        'tech_neg_illiquidity_1m',
        'tech_neg_illiquidity_1m',

        'tech_down_turnover_1m',
        'tech_down_turnover_3m',
    ]

    new_factor_list = [
        'hf_opc_volume_ratio_5d',
        'hf_opc_volume_ratio_10d',
        'hf_opc_volume_ratio_15d',
        'hf_opc_volume_ratio_20d',
        'hf_opc_volume_ratio_30d',
        'event_hgt_sgt_net_inflow_1m',
        'event_hgt_sgt_holding_change_1m',
        'event_hgt_sgt_holding_prop_change_1m',
    ]

    all_factor_list = os.listdir(factor_dir)

    # profitability_factor_list = [f.split('.h5')[0] for f in all_factor_list if f[:14] == 'profitability_']
    # growth_factor_list = [f.split('.h5')[0] for f in all_factor_list if f[:7] == 'growth_']
    profitability_factor_list = [f.split('.h5')[0] for f in all_factor_list if f[:len('profitability_')] == 'profitability_']
    growth_factor_list = [f.split('.h5')[0] for f in all_factor_list if f[:len('growth_')] == 'growth_']
    valuation_factor_list = [f.split('.h5')[0] for f in all_factor_list if f[:len('valuation_')] == 'valuation_']

    # save_sub_dir = 'profitablity_only'
    # label = 'profitablity_only'
    save_sub_dir = 'valuation_only'
    label = 'valuation_only'

    factor_quantile_main(start_date,
                         end_date,
                         valuation_factor_list,
                         quantile=5,            # 分组数目,分组回测专用
                         predictPeriod=5,       # 预测区间,计算rank_ic专用
                         rebalance=20,           # 调仓周期,可选 month_end、month_start和自然数N
                         pool='000905',        # 因子测试股票池
                         benchmark='000905',   # 业绩基准
                         dir_name='public',    # 'public', #读取因子地址，可选:public 公共因子库, advance 风格因子库
                         weight='equal',       # 加权方式，可选：equal  等权、cap 市值加权、ind_adj 基准行业权重配比
                         save_sub_dir=save_sub_dir,
                         label=label,
                         groupby='cap')        # 分组方式，可选 : None 全股票池分组,cap 市值分组


    '''
    factor_list=['tech_turnover_cv_3m',
                 'tech_ff3_dispersion_1m',
                  'tech_network_eigenvector_centrality_1m',
                  'tech_network_degree_centrality_1m',
                  'tech_complex_network_degree_1m',
                  'tech_Carhart4_dispersion_1m',
                  'liquidity_share_turnover_std_3m',
                 'liquidity_share_turnover_3m',
                 'mom_industrialadjust_2m']


    factor_list=['mom_weighted_strength_1m',
                'tech_down_to_up_turnover_3m',
                'tech_down_to_up_vol_1m',
                 'tech_down_turnover_1m',
                'tech_neg_illiquidity_1m',]

    factor_rank_ic_main(start_date,
                        end_date,
                        factor_list,
                        'selected_alpha_rank_ic_12_14',
                        quantile=5,
                        predictPeriod=21,
                        rebalance=21,
                        pool='000905',
                        dir_name='public',
                        weight='ind_adj',
                        groupby='cap')
    '''
